import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CharUtils {
    private static CharUtils instance = new CharUtils();

    private CharUtils() {

    }

    public static CharUtils getInstance() {
        return instance;
    }

    private TokenUtils tokenUtils = TokenUtils.getInstance();
    private List<Object> allText = TokenUtils.getInstance().getAllText();
    private String[] originalText;

    private void filter(String filename) {
        Scanner scanner = null;
        try {
            scanner = new Scanner(new File(filename));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        StringBuilder sb = new StringBuilder();
        while (scanner.hasNextLine()) {
            sb.append(scanner.nextLine());
            sb.append("\n");
        }
//        System.out.println(sb.toString());


//        StringBuilder sb = new StringBuilder("int main(){\n" +
//                "    const int a[4][2] = {{1, 2}, {3, 4}, {5,6}, {7,8}};\n" +
//                "    const int N = 3;\n" +
//                "    int c[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};\n" +
//                "    int d[N + 1][2] = {{1, 2}, {3,0}, {5,0}, {a[3][0], 8}};\n" +
//                "    int e[4][2][1] = {{{d[2][1]}, {c[2][1]}}, {{3}, {4}}, {{5}, {6}}, {{7}, {8}}};\n" +
//                "    putint(e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0]);\n" +
//                "    return 0;\n" +
//                "}\n");
        String pattern = "\\/\\/.*|\\/\\*(\\s|.)*?\\*\\/|\\/\\*(\\s|.)*";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(sb.toString());
        originalText = m.replaceAll(" ").split("\\s+");
    }

    private void split(String string) {
        int len = string.length();
        for (int i = 0; i < len; i++) {
            Character ch = string.charAt(i);
            if (Character.isDigit(ch)) {
                StringBuilder sb = new StringBuilder();
                while (i < len && (Character.isDigit(string.charAt(i)) || string.charAt(i) == 'x' || string.charAt(i) == 'X' || (string.charAt(i) >= 'a' && string.charAt(i) <= 'f') || (string.charAt(i) >= 'A' && string.charAt(i) <= 'F'))) {
                    ch = string.charAt(i);
                    sb.append(ch);
                    i++;
                }
                addNumber(sb.toString());
                i--;
            } else if (Character.isLowerCase(ch) || Character.isUpperCase(ch) || ch == '_') {
                StringBuilder sb = new StringBuilder();
                while (i < len && (Character.isLetterOrDigit(string.charAt(i)) || string.charAt(i) == '_')) {
                    ch = string.charAt(i);
                    sb.append(ch);
                    i++;
                }
                i--;
                if (!tokenUtils.isReserved(sb.toString())) {
                    tokenUtils.getIdentifiers().put(sb.toString(), null);
                }
                allText.add(sb.toString());
            } else if (ch == '=' || ch == '>' || ch == '<') {
                if (i + 1 >= len || (string.charAt(i + 1) != '=')) {
                    allText.add(ch.toString());
                } else {
                    StringBuilder sb = new StringBuilder(ch.toString());
                    sb.append(string.charAt(i + 1));
                    allText.add(sb.toString());
                    i++;
                }
            } else if (tokenUtils.isSymbol(ch.toString())) {
                allText.add(ch.toString());
            } else {
                System.exit(1);
            }
        }
    }

    private void addNumber(String num) {
        try {
            if (num.charAt(0) == '0' && num.length() == 1) {
                allText.add(0);
            } else if (num.charAt(0) == '0' && (num.charAt(1) == 'x' || num.charAt(1) == 'X')) {
                allText.add(Integer.parseInt(num.substring(2, num.length()), 16));
            } else if (num.charAt(0) == '0') {
                allText.add(Integer.parseInt(num, 8));
            } else {
                allText.add(Integer.parseInt(num));
            }
        } catch (NumberFormatException e) {
            System.exit(2);
        }
    }

    private void distinguishAdd() {
        int len = allText.size();
        Object obj;
        for (int index = 0; index < len; index++) {
            obj = allText.get(index);
            if (obj.equals("+") || obj.equals("-")) {
                if (!(index > 0 && index < allText.size() - 1 && isAdd(index))) {
                    if (obj.equals("+")) {
                        allText.set(index, "++");
                    } else {
                        allText.set(index, "--");
                    }
                }
            }
        }
    }

    private boolean isAdd(int index) {
//        if ((allText.get(index - 1).equals(")") && allText.get(index + 1).equals("("))
//                || (allText.get(index - 1).equals(")") && allText.get(index + 1) instanceof Integer)
//                || (allText.get(index - 1) instanceof Integer && allText.get(index + 1).equals("("))
//                || (allText.get(index - 1) instanceof Integer && allText.get(index + 1) instanceof Integer)
//        ) {
//            return true;
//        }
        if ((allText.get(index - 1).equals("]")) || (allText.get(index - 1).equals(")")) || (allText.get(index - 1) instanceof Integer) || (tokenUtils.isIdent(allText.get(index - 1)))) {
            return true;
        }
        return false;
    }


    public void read(String filename) {
        this.filter(filename);
        for (String token : originalText) {
            if (tokenUtils.isReserved(token) || tokenUtils.isSymbol(token)) {
                allText.add(token);
            } else {
                split(token);
            }
        }
        distinguishAdd();
    }

}
